a86f6d3
@@ -19,6 +19,7 @@
package org.springframework.scheduling.annotation;
 import java.lang.reflect.Method;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.IdentityHashMap;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
@@ -111,7 +112,7 @@
public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea
 
 	private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64));
 
-	private final Map<Object, Set<ScheduledTask>> scheduledTasks = new ConcurrentHashMap<>(16);
+	private final Map<Object, Set<ScheduledTask>> scheduledTasks = new IdentityHashMap<>(16);
 
 
 	@Override
@@ -261,8 +262,8 @@
public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea
 					new MethodIntrospector.MetadataLookup<Set<Scheduled>>() {
 						@Override
 						public Set<Scheduled> inspect(Method method) {
-							Set<Scheduled> scheduledMethods =
-									AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);
+							Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(
+									method, Scheduled.class, Schedules.class);
 							return (!scheduledMethods.isEmpty() ? scheduledMethods : null);
 						}
 					});
@@ -300,11 +301,7 @@
public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea
 			String errorMessage =
 					"Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required";
 
-			Set<ScheduledTask> tasks = this.scheduledTasks.get(bean);
-			if (tasks == null) {
-				tasks = new LinkedHashSet<>(4);
-				this.scheduledTasks.put(bean, tasks);
-			}
+			Set<ScheduledTask> tasks = new LinkedHashSet<>(4);
 
 			// Determine initial delay
 			long initialDelay = scheduled.initialDelay();
@@ -398,6 +395,16 @@
public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea
 
 			// Check whether we had any attribute set
 			Assert.isTrue(processedSchedule, errorMessage);
+
+			// Finally register the scheduled tasks
+			synchronized (this.scheduledTasks) {
+				Set<ScheduledTask> registeredTasks = this.scheduledTasks.get(bean);
+				if (registeredTasks == null) {
+					registeredTasks = new LinkedHashSet<>(4);
+					this.scheduledTasks.put(bean, registeredTasks);
+				}
+				registeredTasks.addAll(tasks);
+			}
 		}
 		catch (IllegalArgumentException ex) {
 			throw new IllegalStateException(
@@ -408,7 +415,10 @@
public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea
 
 	@Override
 	public void postProcessBeforeDestruction(Object bean, String beanName) {
-		Set<ScheduledTask> tasks = this.scheduledTasks.remove(bean);
+		Set<ScheduledTask> tasks;
+		synchronized (this.scheduledTasks) {
+			tasks = this.scheduledTasks.remove(bean);
+		}
 		if (tasks != null) {
 			for (ScheduledTask task : tasks) {
 				task.cancel();
@@ -418,18 +428,22 @@
public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea
 
 	@Override
 	public boolean requiresDestruction(Object bean) {
-		return this.scheduledTasks.containsKey(bean);
+		synchronized (this.scheduledTasks) {
+			return this.scheduledTasks.containsKey(bean);
+		}
 	}
 
 	@Override
 	public void destroy() {
-		Collection<Set<ScheduledTask>> allTasks = this.scheduledTasks.values();
-		for (Set<ScheduledTask> tasks : allTasks) {
-			for (ScheduledTask task : tasks) {
-				task.cancel();
+		synchronized (this.scheduledTasks) {
+			Collection<Set<ScheduledTask>> allTasks = this.scheduledTasks.values();
+			for (Set<ScheduledTask> tasks : allTasks) {
+				for (ScheduledTask task : tasks) {
+					task.cancel();
+				}
 			}
+			this.scheduledTasks.clear();
 		}
-		this.scheduledTasks.clear();
 		this.registrar.destroy();
 	}
 
